//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include "ModelDetailStatistic.h"
#include "StringUtilities.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <fstream>
#include <iostream>
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define MAX_SIZE 500000
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ModelDetailStatistic::ModelDetailStatistic () {

  this->detailAccuracyByClass            = new TListE <ModelDetailAccuracy> ();
  this->rootRelativeSquareError          = 0;
  this->relativeAbsoluteError            = 0;
  this->rmsError                         = 0;
  this->meanAbsoluteError                = 0;
  this->complexityImprovementPerInstance = 0;
  this->complexityImprovement            = 0;
  this->classComplexitySchemePerInstance = 0;
  this->classComplexityScheme            = 0;
  this->classComplexityOrderPerInstance  = 0;
  this->classComplexityOrder             = 0;
  this->kBInfoScoreBitsPerInstance       = 0;
  this->kBInfoScoreBits                  = 0;
  this->kBRelativeInfoScore              = 0;
  this->kappa                            = 0;
  this->incorrectlyClassifiedPercentage  = 0;
  this->correctlyClassifiedPercentage    = 0;
  this->totalNumberInstance              = 0;
  this->incorrectlyClassifiedInstance    = 0;
  this->correctlyClassifiedInstance      = 0;
  this->confusionMatrix                  = NULL;

  this->toString                         = new String ();

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ModelDetailStatistic::ModelDetailStatistic (const ModelDetailStatistic& modelDetailStatistic) {

  this->detailAccuracyByClass            = new TListE <ModelDetailAccuracy> (modelDetailStatistic.detailAccuracyByClass);
  this->rootRelativeSquareError          = modelDetailStatistic.rootRelativeSquareError;
  this->relativeAbsoluteError            = modelDetailStatistic.relativeAbsoluteError;
  this->rmsError                         = modelDetailStatistic.rmsError;
  this->meanAbsoluteError                = modelDetailStatistic.meanAbsoluteError;
  this->complexityImprovementPerInstance = modelDetailStatistic.complexityImprovementPerInstance;
  this->complexityImprovement            = modelDetailStatistic.complexityImprovement;
  this->classComplexitySchemePerInstance = modelDetailStatistic.classComplexitySchemePerInstance;
  this->classComplexityScheme            = modelDetailStatistic.classComplexityScheme;
  this->classComplexityOrderPerInstance  = modelDetailStatistic.classComplexityOrderPerInstance;
  this->classComplexityOrder             = modelDetailStatistic.classComplexityOrder;
  this->kBInfoScoreBitsPerInstance       = modelDetailStatistic.kBInfoScoreBitsPerInstance;
  this->kBInfoScoreBits                  = modelDetailStatistic.kBInfoScoreBits;
  this->kBRelativeInfoScore              = modelDetailStatistic.kBRelativeInfoScore;
  this->kappa                            = modelDetailStatistic.kappa;
  this->incorrectlyClassifiedPercentage  = modelDetailStatistic.incorrectlyClassifiedPercentage;
  this->correctlyClassifiedPercentage    = modelDetailStatistic.correctlyClassifiedPercentage;
  this->totalNumberInstance              = modelDetailStatistic.totalNumberInstance;
  this->incorrectlyClassifiedInstance    = modelDetailStatistic.incorrectlyClassifiedInstance;
  this->correctlyClassifiedInstance      = modelDetailStatistic.correctlyClassifiedInstance;

  if (modelDetailStatistic.confusionMatrix) {
    
    this->confusionMatrix = new int* [this->detailAccuracyByClass->Length() - 1];
    for (int i = 0; i < this->detailAccuracyByClass->Length() - 1; i++) {
      
      if (!modelDetailStatistic.confusionMatrix[i]) {
        this->confusionMatrix[i] = NULL;
        continue;
      }
      
      this->confusionMatrix[i] = new int [this->detailAccuracyByClass->Length() - 1];
      
      for (int j = 0; j < this->detailAccuracyByClass->Length() - 1; j++) 
        if (modelDetailStatistic.confusionMatrix[i][j])
          this->confusionMatrix[i][j] = modelDetailStatistic.confusionMatrix[i][j];
        else
          this->confusionMatrix[i][j] = 0;
      
    }
    
  }
  else this->confusionMatrix  = NULL;
  
  this->toString              = new String (modelDetailStatistic.toString);

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ModelDetailStatistic::ModelDetailStatistic (const ModelDetailStatistic* modelDetailStatistic) {

  this->detailAccuracyByClass            = new TListE <ModelDetailAccuracy> (modelDetailStatistic->detailAccuracyByClass);
  this->rootRelativeSquareError          = modelDetailStatistic->rootRelativeSquareError;
  this->relativeAbsoluteError            = modelDetailStatistic->relativeAbsoluteError;
  this->rmsError                         = modelDetailStatistic->rmsError;
  this->meanAbsoluteError                = modelDetailStatistic->meanAbsoluteError;
  this->complexityImprovementPerInstance = modelDetailStatistic->complexityImprovementPerInstance;
  this->complexityImprovement            = modelDetailStatistic->complexityImprovement;
  this->classComplexitySchemePerInstance = modelDetailStatistic->classComplexitySchemePerInstance;
  this->classComplexityScheme            = modelDetailStatistic->classComplexityScheme;
  this->classComplexityOrderPerInstance  = modelDetailStatistic->classComplexityOrderPerInstance;
  this->classComplexityOrder             = modelDetailStatistic->classComplexityOrder;
  this->kBInfoScoreBitsPerInstance       = modelDetailStatistic->kBInfoScoreBitsPerInstance;
  this->kBInfoScoreBits                  = modelDetailStatistic->kBInfoScoreBits;
  this->kBRelativeInfoScore              = modelDetailStatistic->kBRelativeInfoScore;
  this->kappa                            = modelDetailStatistic->kappa;
  this->incorrectlyClassifiedPercentage  = modelDetailStatistic->incorrectlyClassifiedPercentage;
  this->correctlyClassifiedPercentage    = modelDetailStatistic->correctlyClassifiedPercentage;
  this->totalNumberInstance              = modelDetailStatistic->totalNumberInstance;
  this->incorrectlyClassifiedInstance    = modelDetailStatistic->incorrectlyClassifiedInstance;
  this->correctlyClassifiedInstance      = modelDetailStatistic->correctlyClassifiedInstance;
  

  if (modelDetailStatistic->confusionMatrix) {
    
    this->confusionMatrix = new int* [this->detailAccuracyByClass->Length() - 1];
    for (int i = 0; i < this->detailAccuracyByClass->Length() - 1; i++) {
      
      if (!modelDetailStatistic->confusionMatrix[i]) {
        this->confusionMatrix[i] = NULL;
        continue;
      }
      
      this->confusionMatrix[i] = new int [this->detailAccuracyByClass->Length() - 1];
      
      for (int j = 0; j < this->detailAccuracyByClass->Length() - 1; j++) 
        if (modelDetailStatistic->confusionMatrix[i][j])
          this->confusionMatrix[i][j] = modelDetailStatistic->confusionMatrix[i][j];
        else
          this->confusionMatrix[i][j] = 0;
      
    }
    
  }
  else this->confusionMatrix  = NULL;

  this->toString              = new String (modelDetailStatistic->toString);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ModelDetailStatistic::~ModelDetailStatistic () {

  if (this->toString)               delete this->toString;
  
  if (this->confusionMatrix) {
    
    for (int i = 0; i < this->detailAccuracyByClass->Length() - 1; i++)
      if (this->confusionMatrix[i])
        delete[] this->confusionMatrix[i];
    
    delete[] this->confusionMatrix;
    
  }

  if (this->detailAccuracyByClass)  delete this->detailAccuracyByClass;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ModelDetailStatistic::DetailAccuracyByClass (TListE <ModelDetailAccuracy>* detailAccuracyByClass) {

  if (detailAccuracyByClass)
    *(this->detailAccuracyByClass) = *detailAccuracyByClass;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ModelDetailStatistic::RootRelativeSquareError (float rootRelativeSquareError) {

  this->rootRelativeSquareError = rootRelativeSquareError;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ModelDetailStatistic::RelativeAbsoluteError (float relativeAbsoluteError) {

  this->relativeAbsoluteError = relativeAbsoluteError;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ModelDetailStatistic::RmsError (float rmsError) {

  this->rmsError = rmsError;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ModelDetailStatistic::MeanAbsoluteError (float meanAbsoluteError) {

  this->meanAbsoluteError = meanAbsoluteError;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ModelDetailStatistic::ComplexityImprovementPerInstance (float complexityImprovementPerInstance) {

  this->complexityImprovementPerInstance = complexityImprovementPerInstance;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ModelDetailStatistic::ComplexityImprovement (float complexityImprovement) {

  this->complexityImprovement = complexityImprovement;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ModelDetailStatistic::ClassComplexitySchemePerInstance (float classComplexitySchemePerInstance) {

  this->classComplexitySchemePerInstance = classComplexitySchemePerInstance;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ModelDetailStatistic::ClassComplexityScheme (float classComplexityScheme) {

  this->classComplexityScheme = classComplexityScheme;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ModelDetailStatistic::ClassComplexityOrderPerInstance (float classComplexityOrderPerInstance) {

  this->classComplexityOrderPerInstance = classComplexityOrderPerInstance;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ModelDetailStatistic::ClassComplexityOrder (float classComplexityOrder) {

  this->classComplexityOrder = classComplexityOrder;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ModelDetailStatistic::KBInfoScoreBitsPerInstance (float kBInfoScoreBitsPerInstance) {

  this->kBInfoScoreBitsPerInstance = kBInfoScoreBitsPerInstance;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ModelDetailStatistic::KBInfoScoreBits (float kBInfoScoreBits) {

  this->kBInfoScoreBits = kBInfoScoreBits;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ModelDetailStatistic::KBRelativeInfoScore (float kBRelativeInfoScore) {

  this->kBRelativeInfoScore = kBRelativeInfoScore;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ModelDetailStatistic::Kappa (float kappa) {

  this->kappa = kappa;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ModelDetailStatistic::IncorrectlyClassifiedPercentage (float incorrectlyClassifiedPercentage) {

  this->incorrectlyClassifiedPercentage = incorrectlyClassifiedPercentage;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ModelDetailStatistic::CorrectlyClassifiedPercentage (float correctlyClassifiedPercentage) {

  this->correctlyClassifiedPercentage = correctlyClassifiedPercentage;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ModelDetailStatistic::TotalNumberInstance (int totalNumberInstance) {

  this->totalNumberInstance = totalNumberInstance;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ModelDetailStatistic::IncorrectlyClassifiedInstance (int incorrectlyClassifiedInstance) {

  this->incorrectlyClassifiedInstance = incorrectlyClassifiedInstance;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ModelDetailStatistic::CorrectlyClassifiedInstance (int correctlyClassifiedInstance) {

  this->correctlyClassifiedInstance = correctlyClassifiedInstance;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ModelDetailStatistic::ConfusionMatrix (int** confusionMatrix) {

  if (confusionMatrix)
    *(this->confusionMatrix) = *confusionMatrix;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
TListE <ModelDetailAccuracy>* ModelDetailStatistic::DetailAccuracyByClass (void) {

  return this->detailAccuracyByClass;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
float ModelDetailStatistic::RootRelativeSquareError (void) {

  return this->rootRelativeSquareError;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
float ModelDetailStatistic::RelativeAbsoluteError (void) {

  return this->relativeAbsoluteError;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
float ModelDetailStatistic::RmsError (void) {

  return this->rmsError;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
float ModelDetailStatistic::MeanAbsoluteError (void) {

  return this->meanAbsoluteError;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
float ModelDetailStatistic::ComplexityImprovementPerInstance (void) {

  return this->complexityImprovementPerInstance;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
float ModelDetailStatistic::ComplexityImprovement (void) {

  return this->complexityImprovement;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
float ModelDetailStatistic::ClassComplexitySchemePerInstance (void) {

  return this->classComplexitySchemePerInstance;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
float ModelDetailStatistic::ClassComplexityScheme (void) {

  return this->classComplexityScheme;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
float ModelDetailStatistic::ClassComplexityOrderPerInstance (void) {

  return this->classComplexityOrderPerInstance;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
float ModelDetailStatistic::ClassComplexityOrder (void) {

  return this->classComplexityOrder;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
float ModelDetailStatistic::KBInfoScoreBitsPerInstance (void) {

  return this->kBInfoScoreBitsPerInstance;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
float ModelDetailStatistic::KBInfoScoreBits (void) {

  return this->kBInfoScoreBits;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
float ModelDetailStatistic::KBRelativeInfoScore (void) {

  return this->kBRelativeInfoScore;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
float ModelDetailStatistic::Kappa (void) {

  return this->kappa;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
float ModelDetailStatistic::IncorrectlyClassifiedPercentage (void) {

  return this->incorrectlyClassifiedPercentage;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
float ModelDetailStatistic::CorrectlyClassifiedPercentage (void) {

  return this->correctlyClassifiedPercentage;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
int ModelDetailStatistic::TotalNumberInstance (void) {

  return this->totalNumberInstance;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
int ModelDetailStatistic::IncorrectlyClassifiedInstance (void) {

  return this->incorrectlyClassifiedInstance;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
int ModelDetailStatistic::CorrectlyClassifiedInstance (void) {

  return this->correctlyClassifiedInstance;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
int** ModelDetailStatistic::ConfusionMatrix (void) {

  return this->confusionMatrix;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* ModelDetailStatistic::ToString (int numberSpaces) {

  char buffer [MAX_SIZE];
  char spaces [MAX_SIZE];
  
  for (int i = 0; i < numberSpaces; i++)
    spaces[i] = ' ';
  spaces[numberSpaces] = '\0';
  
  this->toString->In("\n");
  
  this->toString->Add(spaces);
  sprintf(buffer, "Correctly Classified Instances   %9d              %8.4f %%\n\0", this->correctlyClassifiedInstance, this->correctlyClassifiedPercentage);
  this->toString->Add(buffer);
  
  this->toString->Add(spaces);
  sprintf(buffer, "Incorrectly Classified Instances %9d              %8.4f %%\n\0", this->incorrectlyClassifiedInstance, this->incorrectlyClassifiedPercentage);
  this->toString->Add(buffer);
  
  this->toString->Add(spaces);
  sprintf(buffer, "Kappa statistic                  %14.4f\n\0", this->kappa);
  this->toString->Add(buffer);
  
  this->toString->Add(spaces);
  sprintf(buffer, "K&B Relative Info Score          %14.4f %%\n\0", this->kBRelativeInfoScore);
  this->toString->Add(buffer);
  
  this->toString->Add(spaces);
  sprintf(buffer, "K&B Information Score            %14.4f bits      %-6.4f bits/instance\n\0", this->kBInfoScoreBits, this->kBInfoScoreBitsPerInstance);
  this->toString->Add(buffer);
  
  this->toString->Add(spaces);
  sprintf(buffer, "Class complexity | order 0       %14.4f bits      %-6.4f bits/instance\n\0", this->classComplexityOrder, this->classComplexityOrderPerInstance);
  this->toString->Add(buffer);
  
  this->toString->Add(spaces);
  sprintf(buffer, "Class complexity | scheme        %14.4f bits %11.4f bits/instance\n\0", this->classComplexityScheme, this->classComplexitySchemePerInstance);
  this->toString->Add(buffer);
  
  this->toString->Add(spaces);
  sprintf(buffer, "Complexity improvement     (Sf)  %14.4f bits %11.4f bits/instance\n\0", this->complexityImprovement, this->complexityImprovementPerInstance);
  this->toString->Add(buffer);
  
  this->toString->Add(spaces);
  sprintf(buffer, "Mean absolute error              %14.4f\n\0", this->meanAbsoluteError);
  this->toString->Add(buffer);
  
  this->toString->Add(spaces);
  sprintf(buffer, "Root mean squared error          %14.4f\n\0", this->rmsError);
  this->toString->Add(buffer);
  
  this->toString->Add(spaces);
  sprintf(buffer, "Relative absolute error          %14.4f %%\n\0", this->relativeAbsoluteError);
  this->toString->Add(buffer);
  
  this->toString->Add(spaces);
  sprintf(buffer, "Root relative squared error      %14.4f %%\n\0", this->rootRelativeSquareError);
  this->toString->Add(buffer);
  
  this->toString->Add(spaces);
  sprintf(buffer, "Total Number of Instances        %9d\n\n\n\0", this->totalNumberInstance);
  this->toString->Add(buffer);
  
  this->toString->Add(spaces);
  sprintf(buffer, "=== Detailed Accuracy By Class ===\n\n\0");
  this->toString->Add(buffer);
  
  this->toString->Add(spaces);
  this->toString->Add("               TP Rate   FP Rate   Precision   Recall  F-Measure   ROC Area  Class\n");
  
  for (int i = 0; i < this->detailAccuracyByClass->Length(); i++) {
    this->toString->Add(spaces);
    this->toString->Add((i < (this->detailAccuracyByClass->Length() - 1))?this->DetailAccuracyByClass()->Get(i)->ToString():this->DetailAccuracyByClass()->Get(i)->ToStringWeightedLine());
    this->toString->Add("\n");
  }
  
  this->toString->Add("\n\n");
  this->toString->Add(spaces);
  sprintf(buffer, "=== Confusion Matrix ===\n\n\0");
  this->toString->Add(buffer);
  
  int lengthHigherNumber = -1;
  
  for (int i = 0; i < this->DetailAccuracyByClass()->Length() - 1; i++) {
    
    if (!this->confusionMatrix[i]) continue;
    
    for (int j = 0; j < this->DetailAccuracyByClass()->Length() - 1; j++) {

      sprintf(buffer, "%d\0", this->confusionMatrix[i][j]);
      lengthHigherNumber = ((int)strlen(buffer) > lengthHigherNumber)?(int)strlen(buffer):lengthHigherNumber;
      
    }
      
  }
  
  char format [MAX_SIZE];
  char letter = 'a';
  
  sprintf(format, "%%%dc \0", lengthHigherNumber);
  
  this->toString->Add(spaces);
  this->toString->Add(" ");
  for (int i = 0; i < this->DetailAccuracyByClass()->Length() - 1; i++) {
    sprintf(buffer, format, (char)(letter + i));
    this->toString->Add(buffer);
  }
  this->toString->Add("  <-- classified as\n");

  sprintf(format, "%%%dd \0", lengthHigherNumber);

  if (this->confusionMatrix) {
    
    letter = 'a';
    
    for (int i = 0; i < this->DetailAccuracyByClass()->Length() - 1; i++) {

      this->toString->Add(spaces);
      this->toString->Add(" ");
      
      for (int j = 0; j < this->DetailAccuracyByClass()->Length() - 1; j++) {

        sprintf(buffer, format, this->confusionMatrix[i][j]);
        this->toString->Add(buffer);

      }
      
      sprintf(buffer, "|   %c = %s\n\0", letter++, this->DetailAccuracyByClass()->Get(i)->ClassName()->Out());
      this->toString->Add(buffer);
      
    }

  }
  
  return this->toString;  

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* ModelDetailStatistic::ToString (void) {

  return this->ToString(0);

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* ModelDetailStatistic::ToStringConfusionMatrix (void) {

  char buffer [MAX_SIZE];
  
  sprintf(buffer, "=== Confusion Matrix ===\n\0");
  this->toString->Add(buffer);
  
  int lengthHigherNumber = -1;
  
  for (int i = 0; i < this->DetailAccuracyByClass()->Length() - 1; i++) {
    
    if (!this->confusionMatrix[i]) break;
    
    for (int j = 0; j < this->DetailAccuracyByClass()->Length() - 1; j++) {

      if (!this->confusionMatrix[i][j]) break;
      
      sprintf(buffer, "%d\0", this->confusionMatrix[i][j]);
      
      if (lengthHigherNumber < strlen(buffer))
        lengthHigherNumber = strlen(buffer);
      
    }
      
  }
  
  char format [MAX_SIZE];
  char letter = 'a';
  
  sprintf(format, "%%%dc \0", lengthHigherNumber);
  
  this->toString->Add(" ");
  for (int i = 0; i < this->DetailAccuracyByClass()->Length() - 1; i++) {
    sprintf(buffer, format, (char)(letter + i));
    this->toString->Add(buffer);
  }
  this->toString->Add("  <-- classified as\n");

  sprintf(format, "%%%dd \0", lengthHigherNumber);

  if (this->confusionMatrix) {
    
    letter = 'a';
    
    for (int i = 0; i < this->DetailAccuracyByClass()->Length() - 1; i++) {

      this->toString->Add(" ");
      
      for (int j = 0; j < this->DetailAccuracyByClass()->Length() - 1; j++) {

        sprintf(buffer, format, this->confusionMatrix[i][j]);
        this->toString->Add(buffer);

      }
      
      sprintf(buffer, "|   %c = %s\n\0", letter++, this->DetailAccuracyByClass()->Get(i)->ClassName()->Out());
      this->toString->Add(buffer);
      
    }

  }
  
  return this->toString;  

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ModelDetailStatistic::LoadFromData (String* data) {
  
  if (!data || !data->Length())
    return false;

  TListE <String>* lines               = new TListE <String> ();
  char*            parts               = NULL;
  bool             loadDetailAccuracy  = false;
  bool             loadConfusionMatrix = false;
  int              counter             = 0;

  parts = strtok(data->Out(), "\n");
  while (parts) {
    lines->Add(new String(parts));
    parts = strtok(NULL, "\n");
  }  

  lines->SetInitial();
  while (lines->SetNext()) {
    
    char* line = lines->GetCurrent()->Out();
    
    if      (strstr(line, "Correctly Classified Instances")) {
      this->correctlyClassifiedInstance   = StringUtilities::GetIntInPosition(line, 4);
      this->correctlyClassifiedPercentage = StringUtilities::GetFloatInPosition(line, 5);
    }
    else if (strstr(line, "Incorrectly Classified Instances")) {
      this->incorrectlyClassifiedInstance   = StringUtilities::GetIntInPosition(line, 4);
      this->incorrectlyClassifiedPercentage = StringUtilities::GetFloatInPosition(line, 5);
    }
    else if (strstr(line, "Kappa statistic")) {
      this->kappa = StringUtilities::GetFloatInPosition(line, 3);
    }
    else if (strstr(line, "K&B Relative Info Score") || strstr(line, "K^B Relative Info Score")) {
      this->kBRelativeInfoScore = StringUtilities::GetFloatInPosition(line, 5);
    }
    else if (strstr(line, "K&B Information Score") || strstr(line, "K^B Information Score")) {
      this->kBInfoScoreBits            = StringUtilities::GetFloatInPosition(line, 4);
      this->kBInfoScoreBitsPerInstance = StringUtilities::GetFloatInPosition(line, 6);
    }
    else if (strstr(line, "Class complexity | order 0")) {
      this->classComplexityOrder            = StringUtilities::GetFloatInPosition(line, 6);
      this->classComplexityOrderPerInstance = StringUtilities::GetFloatInPosition(line, 8);
    }
    else if (strstr(line, "Class complexity | scheme")) {
      this->classComplexityScheme            = StringUtilities::GetFloatInPosition(line, 5);
      this->classComplexitySchemePerInstance = StringUtilities::GetFloatInPosition(line, 7);
    }
    else if (strstr(line, "Complexity improvement")) {
      this->complexityImprovement            = StringUtilities::GetFloatInPosition(line, 4);
      this->complexityImprovementPerInstance = StringUtilities::GetFloatInPosition(line, 6);
    }
    else if (strstr(line, "Mean absolute error")) {
      this->meanAbsoluteError = StringUtilities::GetFloatInPosition(line, 4);
    }
    else if (strstr(line, "Root mean squared error")) {
      this->rmsError = StringUtilities::GetFloatInPosition(line, 5);
    }
    else if (strstr(line, "Relative absolute error")) {
      this->relativeAbsoluteError = StringUtilities::GetFloatInPosition(line, 4);
    }
    else if (strstr(line, "Root relative squared error")) {
      this->rootRelativeSquareError = StringUtilities::GetFloatInPosition(line, 5);
    }
    else if (strstr(line, "Total Number of Instances")) {
      this->totalNumberInstance = StringUtilities::GetIntInPosition(line, 5);
    }
    else if (strstr(line, "Detailed Accuracy By Class")) {
       loadDetailAccuracy = true;
       continue;
    }
    else if (strstr(line, "Confusion Matrix")) {
       loadConfusionMatrix = true;
       continue;
    }
    
    if (loadDetailAccuracy) {
      
      if (StringUtilities::CountNumberString(line) < 7 || strstr(line, "F-Measure"))
        continue;
      
      ModelDetailAccuracy* newModelDetailAccuracy = new ModelDetailAccuracy ();
      
      int pos = (strstr(line, "Weighted Avg."))?2:0;
      
      newModelDetailAccuracy->TruePositiveRate(StringUtilities::GetFloatInPosition(line, pos + 1));
      newModelDetailAccuracy->FalsePositiveRate(StringUtilities::GetFloatInPosition(line, pos + 2));
      newModelDetailAccuracy->Precision(StringUtilities::GetFloatInPosition(line, pos + 3));
      newModelDetailAccuracy->Recall(StringUtilities::GetFloatInPosition(line, pos + 4));
      newModelDetailAccuracy->FMeasure(StringUtilities::GetFloatInPosition(line, pos + 5));
      newModelDetailAccuracy->RocArea(StringUtilities::GetFloatInPosition(line, pos + 6));
      
      if (strstr(line, "Weighted Avg.")) {
        newModelDetailAccuracy->ClassName(new String("weightedAvg"));
        loadDetailAccuracy = false;
        this->confusionMatrix = new int* [this->detailAccuracyByClass->Length()];
        for (int i = 0; i < this->detailAccuracyByClass->Length(); i++) {
          this->confusionMatrix[i] = new int [this->detailAccuracyByClass->Length()];
          for (int j = 0; j < this->detailAccuracyByClass->Length(); j++)
            this->confusionMatrix[i][j] = 0;
        }
      }  
      else {
        char* result = NULL;
        result = StringUtilities::GetStringInPosition(line, pos + 7, result);
        newModelDetailAccuracy->ClassName(new String(result));
        if (result) delete result;
      }
      
      this->detailAccuracyByClass->Add(newModelDetailAccuracy);
      
      continue;
      
    }
    
    if (loadConfusionMatrix) {
      
      if (StringUtilities::CountNumberString(line) < 3 || strstr(line, "classified as"))
        continue;
      
      for (int i = 0; i < this->detailAccuracyByClass->Length() - 1; i++)
        this->confusionMatrix[counter][i] = StringUtilities::GetFloatInPosition(line, i + 1);
        
      if (counter++ == this->detailAccuracyByClass->Length() - 1)
        break;
      
    }
    
  }
  
  if (lines) delete lines;
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ModelDetailStatistic ModelDetailStatistic::operator= (const ModelDetailStatistic& modelDetailStatistic) {

  *(this->detailAccuracyByClass)         = *(modelDetailStatistic.detailAccuracyByClass);
  this->rootRelativeSquareError          = modelDetailStatistic.rootRelativeSquareError;
  this->relativeAbsoluteError            = modelDetailStatistic.relativeAbsoluteError;
  this->rmsError                         = modelDetailStatistic.rmsError;
  this->meanAbsoluteError                = modelDetailStatistic.meanAbsoluteError;
  this->complexityImprovementPerInstance = modelDetailStatistic.complexityImprovementPerInstance;
  this->complexityImprovement            = modelDetailStatistic.complexityImprovement;
  this->classComplexitySchemePerInstance = modelDetailStatistic.classComplexitySchemePerInstance;
  this->classComplexityScheme            = modelDetailStatistic.classComplexityScheme;
  this->classComplexityOrderPerInstance  = modelDetailStatistic.classComplexityOrderPerInstance;
  this->classComplexityOrder             = modelDetailStatistic.classComplexityOrder;
  this->kBInfoScoreBitsPerInstance       = modelDetailStatistic.kBInfoScoreBitsPerInstance;
  this->kBInfoScoreBits                  = modelDetailStatistic.kBInfoScoreBits;
  this->kBRelativeInfoScore              = modelDetailStatistic.kBRelativeInfoScore;
  this->kappa                            = modelDetailStatistic.kappa;
  this->incorrectlyClassifiedPercentage  = modelDetailStatistic.incorrectlyClassifiedPercentage;
  this->correctlyClassifiedPercentage    = modelDetailStatistic.correctlyClassifiedPercentage;
  this->totalNumberInstance              = modelDetailStatistic.totalNumberInstance;
  this->incorrectlyClassifiedInstance    = modelDetailStatistic.incorrectlyClassifiedInstance;
  this->correctlyClassifiedInstance      = modelDetailStatistic.correctlyClassifiedInstance;
  
  if (modelDetailStatistic.confusionMatrix) {
    
    this->confusionMatrix = new int* [this->detailAccuracyByClass->Length() - 1];
    for (int i = 0; i < this->detailAccuracyByClass->Length() - 1; i++) {
      
      if (!modelDetailStatistic.confusionMatrix[i]) {
        this->confusionMatrix[i] = NULL;
        continue;
      }
      
      this->confusionMatrix[i] = new int [this->detailAccuracyByClass->Length() - 1];
      
      for (int j = 0; j < this->detailAccuracyByClass->Length() - 1; j++) 
        if (modelDetailStatistic.confusionMatrix[i][j])
          this->confusionMatrix[i][j] = modelDetailStatistic.confusionMatrix[i][j];
        else
          this->confusionMatrix[i][j] = 0;
      
    }
    
  }
  else this->confusionMatrix = NULL;

  *(this->toString)          = *(modelDetailStatistic.toString);

  return *this;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
